package htwt

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"strconv"
	"strings"
	"syscall"
	"time"

	"gitee.com/lilihli/connector/winapi"
	"github.com/lxn/win"
)

// HtwtWnd 下单主窗口信息
type HtwtWnd struct {
	hwnd      win.HWND
	workWnd   *WorkWnd
	statusWnd *StatusWnd
}

// NewHtwtWnd new HtwtWnd
func NewHtwtWnd() *HtwtWnd {
	this := &HtwtWnd{}
	this.workWnd = NewWorkWnd()
	this.statusWnd = NewStatusWnd()
	return this
}

// UpdateWindowHandle 更新窗口句柄
func (htwtWnd *HtwtWnd) UpdateWindowHandle() error {
	hwnd := win.FindWindow(nil, syscall.StringToUTF16Ptr("网上股票交易系统5.0"))
	if hwnd == 0 {
		return fmt.Errorf("未找到下单软件窗口，请确认下单软件已启动")
	}
	htwtWnd.hwnd = hwnd
	htwtWnd.workWnd.SetParentWnd(hwnd)
	err := htwtWnd.workWnd.UpdateWindowHandle()
	if err != nil {
		return fmt.Errorf("htwtWnd.workWnd.UpdateWindowHandle failed, %v", err)
	}
	htwtWnd.statusWnd.SetParentWnd(hwnd)
	err = htwtWnd.statusWnd.UpdateWindowHandle()
	if err != nil {
		return fmt.Errorf("htwtWnd.statusWnd.UpdateWindowHandle failed, %v", err)
	}
	return nil
}

// CloseUnimportancePopWindow 关闭不重要的弹出窗口
func (htwtWnd *HtwtWnd) CloseUnimportancePopWindow() {
	CloseUnimportancePopWindow(htwtWnd.hwnd)
}

// WorkWnd 工作区域窗口
type WorkWnd struct {
	parent    win.HWND
	hwnd      win.HWND
	buyWnd    *BuyWnd
	saleWnd   *SaleWnd
	cancelWnd *CancelWnd
	queryWnd  *QueryWnd
}

// NewWorkWnd new WorkWnd
func NewWorkWnd() *WorkWnd {
	this := &WorkWnd{}
	this.buyWnd = NewBuyWnd()
	this.saleWnd = NewSaleWnd()
	this.cancelWnd = NewCancelWnd()
	this.queryWnd = NewQueryWnd()
	return this
}

// SetParentWnd 设置父窗口句柄
func (workWnd *WorkWnd) SetParentWnd(parentWnd win.HWND) {
	workWnd.parent = parentWnd
}

// UpdateWindowHandle 更新窗口句柄
func (workWnd *WorkWnd) UpdateWindowHandle() error {
	hwnd := win.GetDlgItem(workWnd.parent, 0xe900)
	if hwnd == 0 {
		return fmt.Errorf("未找到工作窗口")
	}
	workWnd.hwnd = hwnd

	workWnd.buyWnd.SetParentWnd(hwnd)
	workWnd.saleWnd.SetParentWnd(hwnd)
	workWnd.cancelWnd.SetParentWnd(hwnd)
	workWnd.queryWnd.SetParentWnd(hwnd)

	//没有初始化的窗口进行初始化
	if workWnd.buyWnd.FindSelf() == 0 {
		workWnd.buyWnd.Show()
		time.Sleep(time.Millisecond * 500)
	}
	if workWnd.saleWnd.FindSelf() == 0 {
		workWnd.saleWnd.Show()
		time.Sleep(time.Millisecond * 500)
	}
	if workWnd.cancelWnd.FindSelf() == 0 {
		workWnd.cancelWnd.Show()
		time.Sleep(time.Millisecond * 500)
	}
	if workWnd.queryWnd.FindSelf() == 0 {
		workWnd.queryWnd.Show()
		time.Sleep(time.Millisecond * 500)
	}

	err := workWnd.buyWnd.UpdateWindowHandle()
	if err != nil {
		return fmt.Errorf("workWnd.buyWnd.UpdateWindowHandle failed, %v", err)
	}
	err = workWnd.saleWnd.UpdateWindowHandle()
	if err != nil {
		return fmt.Errorf("workWnd.saleWnd.UpdateWindowHandle failed, %v", err)
	}
	err = workWnd.cancelWnd.UpdateWindowHandle()
	if err != nil {
		return fmt.Errorf("workWnd.cancelWnd.UpdateWindowHandle failed, %v", err)
	}
	err = workWnd.queryWnd.UpdateWindowHandle()
	if err != nil {
		return fmt.Errorf("workWnd.queryWnd.UpdateWindowHandle failed, %v", err)
	}
	return nil
}

// BaseWnd 右侧区域窗口基类
type BaseWnd struct {
	name   string //ctrlID 控件的标题
	ctrlID int32  //该窗口中的某个控件的ID，用来识别是否该窗口
	hotKey uint32 //热键，买入为 win.VK_F1, 卖出为 win.VK_F2
	parent win.HWND
}

// SetParentWnd 设置父窗口句柄
func (baseWnd *BaseWnd) SetParentWnd(parentWnd win.HWND) {
	baseWnd.parent = parentWnd
}

// FindSelf 从父窗口中找到自己
func (baseWnd *BaseWnd) FindSelf() win.HWND {
	return winapi.FindChildWindowHasCtrl(baseWnd.parent, baseWnd.ctrlID, baseWnd.name)
}

// Show 切换到买入页面
func (baseWnd *BaseWnd) Show() error {
	err := winapi.KeybdEventCustom(win.GetParent(baseWnd.parent), win.WM_KEYDOWN, baseWnd.hotKey)
	if err != nil {
		return fmt.Errorf("KeybdEventCustom failed, %v", err)
	}
	return nil
}

type StatusWnd struct {
	BaseWnd
	hwnd win.HWND
}

// NewStatusWnd new StatusWnd
func NewStatusWnd() *StatusWnd {
	this := &StatusWnd{}
	this.name = ""
	this.ctrlID = 0xe801
	this.hotKey = 0
	return this
}

func unicode2string(in []byte) (to string, err error) {
	bl := len(in)
	br := bytes.NewReader(in)
	var out []rune
	for i := 0; i < bl; i += 2 {
		var r uint16
		err = binary.Read(br, binary.LittleEndian, &r)
		if err != nil {
			return
		}
		out = append(out, rune(r))
	}
	to = string(out)
	return
}

// UpdateWindowHandle 更新窗口句柄
func (statusWnd *StatusWnd) UpdateWindowHandle() error {
	hwnd := win.GetDlgItem(statusWnd.parent, 0xe801)
	if hwnd == 0 {
		return fmt.Errorf("未找到状态栏窗口")
	}
	statusWnd.hwnd = hwnd
	return nil
}

func (statusWnd *StatusWnd) GetAccountName() (string, error) {
	var processId uint32
	win.GetWindowThreadProcessId(statusWnd.parent, &processId)
	processHandle, err := syscall.OpenProcess(winapi.PROCESS_ALL_ACCESS, false, processId)
	if err != nil {
		return "", fmt.Errorf("syscall.OpenProcess failed, %v", err)
	}

	hwnd := statusWnd.hwnd

	// vCount := win.SendMessage(hwnd, win.SB_GETPARTS, 0, 0)
	// fmt.Println(vCount)

	textLength := win.SendMessage(hwnd, win.SB_GETTEXTLENGTH, uintptr(2), 0)
	bufferSize := int32(textLength&0xffff)*2 + 1

	pVirtualBuffer, err := winapi.VirtualAllocEx(processHandle, bufferSize)
	if err != nil {
		return "", fmt.Errorf("VirtualAllocEx failed, %v", err)
	}
	defer winapi.VirtualFreeEx(processHandle, pVirtualBuffer)

	textLength = win.SendMessage(hwnd, win.SB_GETTEXT, uintptr(2), uintptr(pVirtualBuffer))
	bufferSize = int32(textLength&0xffff) * 2

	buf, err := winapi.ReadProcessMemory(processHandle, pVirtualBuffer, bufferSize)
	if err != nil {
		return "", fmt.Errorf("ReadProcessMemory failed, %v", err)
	}
	accountName, err := unicode2string(buf)
	if err != nil {
		return "", fmt.Errorf("unicode2string failed, %v", err)
	}
	fmt.Println(accountName)

	return accountName, nil
}

// BuySaleWnd 买入股票窗口
type BuySaleWnd struct {
	BaseWnd
	hwnd        win.HWND //买入页面的窗口句柄
	tenPriceWnd TenPriceWnd
}

// UpdateWindowHandle 更新窗口句柄
func (buySaleWnd *BuySaleWnd) UpdateWindowHandle() error {
	hwnd := buySaleWnd.FindSelf()
	if hwnd == 0 {
		return fmt.Errorf("未找到 %s 窗口,ctrlID=%x", buySaleWnd.name, buySaleWnd.ctrlID)
	}
	buySaleWnd.hwnd = hwnd

	buySaleWnd.tenPriceWnd.SetParentWnd(buySaleWnd.hwnd)
	err := buySaleWnd.tenPriceWnd.UpdateWindowHandle()
	if err != nil {
		return fmt.Errorf("buySaleWnd.tenPriceWnd.UpdateWindowHandle failed, %v", err)
	}
	return nil
}

// FillStockCode 填充证券代码输入框
func (buySaleWnd *BuySaleWnd) FillStockCode(code string) error {
	err := winapi.SetDlgItemText(buySaleWnd.hwnd, 0x408, code)
	if err != nil {
		return fmt.Errorf("SetDlgItemText failed, %v", err)
	}
	return nil
}

// FillPrice 填充买入价格输入框
func (buySaleWnd *BuySaleWnd) FillPrice(price float64) error {
	err := winapi.SetDlgItemText(buySaleWnd.hwnd, 0x409, strconv.FormatFloat(price, 'f', 2, 64))
	if err != nil {
		return fmt.Errorf("SetDlgItemText failed, %v", err)
	}
	return nil
}

// FillAmount 填充买入数量输入框
func (buySaleWnd *BuySaleWnd) FillAmount(amount uint64) error {
	err := winapi.SetDlgItemText(buySaleWnd.hwnd, 0x40a, strconv.FormatUint(amount, 10))
	if err != nil {
		return fmt.Errorf("SetDlgItemText failed, %v", err)
	}
	return nil
}

// BuySale 买卖，买入窗口则是买入，卖出窗口则是卖出
func (buySaleWnd *BuySaleWnd) BuySale(code string, price float64, amount uint64) (int, error) {
	//关闭不重要的弹出窗口,以免影响委托确认窗口和结果窗口内容的获取
	topWnd := win.GetParent(buySaleWnd.parent)
	CloseUnimportancePopWindow(topWnd)

	err := buySaleWnd.FillStockCode(code)
	if err != nil {
		return 0, fmt.Errorf("buySaleWnd.FillStockCode failed, %v", err)
	}
	err = buySaleWnd.FillPrice(price)
	if err != nil {
		return 0, fmt.Errorf("buySaleWnd.FillPrice failed, %v", err)
	}
	err = buySaleWnd.FillAmount(amount)
	if err != nil {
		return 0, fmt.Errorf("buySaleWnd.FillAmount failed, %v", err)
	}
	hwnd := win.GetDlgItem(buySaleWnd.hwnd, 0x3ee)
	if hwnd == 0 {
		return 0, fmt.Errorf("没有找到 %s 的按钮", buySaleWnd.name)
	}
	win.SendMessage(hwnd, win.WM_LBUTTONDOWN, 0, 0)
	win.PostMessage(hwnd, win.WM_LBUTTONUP, 0, 0)

	for i := 0; ; i++ {
		time.Sleep(time.Millisecond * 100)
		delegationWnd := win.GetWindow(topWnd, win.GW_ENABLEDPOPUP)
		if delegationWnd != 0 {
			//需要先判断是否是委托确认窗口
			title, err := winapi.GetDlgItemText(delegationWnd, 0x555)
			if err != nil {
				return 0, fmt.Errorf("GetDlgItemText failed, %v", err)
			}
			if title != "委托确认" {
				return 0, fmt.Errorf("委托窗口的标题不符合")
			}
			//获取 是(Y) 按钮
			okBtnWnd := win.GetDlgItem(delegationWnd, 0x6)
			if okBtnWnd == 0 {
				return 0, fmt.Errorf("没有找到委托确认窗口中的 是 按钮")
			}
			win.SendMessage(okBtnWnd, win.WM_LBUTTONDOWN, 0, 0)
			win.SendMessage(okBtnWnd, win.WM_LBUTTONUP, 0, 0)
			break
		}
		if i > 10 {
			return 0, fmt.Errorf("没有找到委托确认窗口")
		}
	}

	ContractNo := 0
	for i := 0; ; i++ {
		time.Sleep(time.Millisecond * 100)
		resultWnd := win.GetWindow(topWnd, win.GW_ENABLEDPOPUP)
		if resultWnd != 0 {
			text, err := winapi.GetDlgItemText(resultWnd, 0x555)
			// if err != nil {
			// 	return 0, fmt.Errorf("获取窗口标题失败, %v", err)
			// }
			// if text == "风险提示" {
			// 	okBtnWnd := win.GetDlgItem(resultWnd, 0x1)
			// 	if okBtnWnd == 0 {
			// 		return 0, fmt.Errorf("没有找到风险提示窗口中的 是 按钮")
			// 	}
			// 	win.SendMessage(okBtnWnd, win.WM_LBUTTONDOWN, 0, 0)
			// 	win.SendMessage(okBtnWnd, win.WM_LBUTTONUP, 0, 0)
			// 	continue
			// }
			if err == nil {
				if text == "风险提示" {
					okBtnWnd := win.GetDlgItem(resultWnd, 0x1)
					if okBtnWnd == 0 {
						return 0, fmt.Errorf("没有找到风险提示窗口中的 是 按钮")
					}
					win.SendMessage(okBtnWnd, win.WM_LBUTTONDOWN, 0, 0)
					win.SendMessage(okBtnWnd, win.WM_LBUTTONUP, 0, 0)
					continue
				}
			}

			text, err = winapi.GetDlgItemText(resultWnd, 0x3ec)
			if err != nil {
				continue
				// return 0, fmt.Errorf("获取委托结果窗口中 合同编号 失败, %v", err)
			}
			text = strings.ReplaceAll(text, "。", "")
			ret := strings.Split(text, "合同编号：")
			if len(ret) != 2 {
				return 0, fmt.Errorf("获取委托结果窗口中 合同编号 失败, strings.Split %s, %v", text, err)
			}
			num, err := strconv.Atoi(ret[1])
			if err != nil {
				return 0, fmt.Errorf("获取委托结果窗口中 合同编号 失败, strconv.Atoi %s, %v", ret[1], err)
			}
			ContractNo = num

			text, err = winapi.GetDlgItemText(resultWnd, 0x2)
			if err != nil {
				return 0, fmt.Errorf("获取委托结果窗口中 确定 按钮的文字失败, %v", err)
			}
			if text != "确定" {
				return 0, fmt.Errorf("委托结果窗口中的 确定 按钮的文字不正确")
			}

			okBtnWnd := win.GetDlgItem(resultWnd, 0x2)
			if okBtnWnd == 0 {
				return 0, fmt.Errorf("没有找到委托结果窗口中的 确定 按钮")
			}
			win.SendMessage(okBtnWnd, win.WM_LBUTTONDOWN, 0, 0)
			win.SendMessage(okBtnWnd, win.WM_LBUTTONUP, 0, 0)
			break
		}
		if i > 50 {
			return 0, fmt.Errorf("没有找到委托结果窗口")
		}
	}
	return ContractNo, nil
}

// BuyWnd 买入窗口
type BuyWnd struct {
	BuySaleWnd
}

// NewBuyWnd new BuyWnd
func NewBuyWnd() *BuyWnd {
	this := &BuyWnd{}
	this.name = "买入股票"
	this.ctrlID = 0x5c6
	this.hotKey = win.VK_F1
	return this
}

// Buy 买入
func (buyWnd *BuyWnd) Buy(code string, price float64, amount uint64) (int, error) {
	return buyWnd.BuySale(code, price, amount)
}

// SaleWnd 卖出窗口
type SaleWnd struct {
	BuySaleWnd
}

// NewSaleWnd new SaleWnd
func NewSaleWnd() *SaleWnd {
	this := &SaleWnd{}
	this.name = "卖出股票"
	this.ctrlID = 0x5c6
	this.hotKey = win.VK_F2
	return this
}

// Sale 卖出
func (saleWnd *SaleWnd) Sale(code string, price float64, amount uint64) (int, error) {
	return saleWnd.BuySale(code, price, amount)
}

// CancelWnd 撤单页面
type CancelWnd struct {
	BaseWnd
	hwnd win.HWND
}

// NewCancelWnd new CancelWnd
func NewCancelWnd() *CancelWnd {
	this := &CancelWnd{}
	this.name = "撤单"
	this.ctrlID = 0x44b
	this.hotKey = win.VK_F3
	return this
}

// UpdateWindowHandle 更新窗口句柄
func (cancelWnd *CancelWnd) UpdateWindowHandle() error {
	hwnd := cancelWnd.FindSelf()
	if hwnd == 0 {
		return fmt.Errorf("未找到撤单窗口")
	}
	cancelWnd.hwnd = hwnd
	return nil
}

// Cancel 撤单
func (cancelWnd *CancelWnd) Cancel() {

}

// QueryWnd 撤单页面
type QueryWnd struct {
	BaseWnd
	hwnd win.HWND
}

// NewQueryWnd new QueryWnd
func NewQueryWnd() *QueryWnd {
	this := &QueryWnd{}
	this.name = "查询资金股票"
	this.ctrlID = 0x5c6
	this.hotKey = win.VK_F4
	return this
}

// UpdateWindowHandle 更新窗口句柄
func (queryWnd *QueryWnd) UpdateWindowHandle() error {
	hwnd := queryWnd.FindSelf()
	if hwnd == 0 {
		return fmt.Errorf("未找到查询资金股票窗口")
	}
	queryWnd.hwnd = hwnd
	return nil
}

// QueryWndInfo 查询窗口信息
type QueryWndInfo struct {
	FundBalance        float64 //资金余额
	WithdrawableAmount float64 //可取金额
	LockAmount         float64 //冻结金额
	StockMarketValue   float64 //股票市值
	AvailableAmount    float64 //可用金额
	TotalAssets        float64 //总资产
	CashAssets         float64 //现金资产
}

// Info 获取信息
func (queryWnd *QueryWnd) Info() (*QueryWndInfo, error) {
	var info QueryWndInfo
	list := []struct {
		CtrlID int32
		ErrWnd error
		Value  *float64
	}{
		{
			CtrlID: 0x3f4,
			ErrWnd: fmt.Errorf("没有找到资金余额窗口"),
			Value:  &info.FundBalance,
		}, {
			CtrlID: 0x3f9,
			ErrWnd: fmt.Errorf("没有找到可取金额窗口"),
			Value:  &info.WithdrawableAmount,
		}, {
			CtrlID: 0x3f5,
			ErrWnd: fmt.Errorf("没有找到冻结金额窗口"),
			Value:  &info.LockAmount,
		}, {
			CtrlID: 0x3f6,
			ErrWnd: fmt.Errorf("没有找到股票市值窗口"),
			Value:  &info.StockMarketValue,
		}, {
			CtrlID: 0x3f8,
			ErrWnd: fmt.Errorf("没有找到可用金额窗口"),
			Value:  &info.AvailableAmount,
		}, {
			CtrlID: 0x3f7,
			ErrWnd: fmt.Errorf("没有找到总资产窗口"),
			Value:  &info.TotalAssets,
		}, {
			CtrlID: 0x5cb,
			ErrWnd: fmt.Errorf("没有找到现金资产窗口"),
			Value:  &info.CashAssets,
		},
	}
	for _, item := range list {
		hwnd := win.GetDlgItem(queryWnd.hwnd, item.CtrlID)
		if hwnd == 0 {
			return nil, item.ErrWnd
		}

		str := winapi.GetWindowText(hwnd)
		value, err := strconv.ParseFloat(str, 64)
		if err != nil {
			return nil, fmt.Errorf("strconv.ParseFloat %s failed, %v", str, err)
		}
		*item.Value = value
	}
	// buf, _ := json.Marshal(&info)
	// fmt.Println(string(buf))
	return &info, nil
}

// TenPriceWnd 十档价格窗口
type TenPriceWnd struct {
	parent win.HWND
	hwnd   win.HWND
}

// SetParentWnd 设置父窗口句柄
func (tenPriceWnd *TenPriceWnd) SetParentWnd(parentWnd win.HWND) {
	tenPriceWnd.parent = parentWnd
}

// UpdateWindowHandle 更新窗口句柄
func (tenPriceWnd *TenPriceWnd) UpdateWindowHandle() error {
	hwnd := winapi.FindChildWindowHasCtrl(tenPriceWnd.parent, 0x6ca, "卖五")
	if hwnd == 0 {
		return fmt.Errorf("没有找到十档价格窗口")
	}
	tenPriceWnd.hwnd = hwnd
	return nil
}

// TenPriceInfo 十档价格信息
type TenPriceInfo struct {
	Sale5Price     float64
	Sale5Amount    uint64
	Sale4Price     float64
	Sale4Amount    uint64
	Sale3Price     float64
	Sale3Amount    uint64
	Sale2Price     float64
	Sale2Amount    uint64
	Sale1Price     float64
	Sale1Amount    uint64
	Buy1Price      float64
	Buy1Amount     uint64
	Buy2Price      float64
	Buy2Amount     uint64
	Buy3Price      float64
	Buy3Amount     uint64
	Buy4Price      float64
	Buy4Amount     uint64
	Buy5Price      float64
	Buy5Amount     uint64
	UpLimitPrice   float64 //涨停价
	DownLimitPrice float64 //跌停价
}

// Sale1 得到卖一价格和数量
func (tenPriceWnd *TenPriceWnd) Sale1() (price float64, amount uint64, err error) {
	var priceCtrlID int32 = 0x3fd
	var amountCtrlID int32 = 0x3f8
	return tenPriceWnd.getRow(priceCtrlID, amountCtrlID, "卖一")
}

// Buy1 得到买一价格和数量
func (tenPriceWnd *TenPriceWnd) Buy1() (price float64, amount uint64, err error) {
	var priceCtrlID int32 = 0x3fa
	var amountCtrlID int32 = 0x3f6
	return tenPriceWnd.getRow(priceCtrlID, amountCtrlID, "买一")
}
func (tenPriceWnd *TenPriceWnd) Buy2() (price float64, amount uint64, err error) {
	var priceCtrlID int32 = 0x401
	var amountCtrlID int32 = 0x3f5
	return tenPriceWnd.getRow(priceCtrlID, amountCtrlID, "买二")
}
func (tenPriceWnd *TenPriceWnd) Buy3() (price float64, amount uint64, err error) {
	var priceCtrlID int32 = 0x402
	var amountCtrlID int32 = 0x3f4
	return tenPriceWnd.getRow(priceCtrlID, amountCtrlID, "买三")
}
func (tenPriceWnd *TenPriceWnd) Buy4() (price float64, amount uint64, err error) {
	var priceCtrlID int32 = 0x40b
	var amountCtrlID int32 = 0x3f7
	return tenPriceWnd.getRow(priceCtrlID, amountCtrlID, "买四")
}
func (tenPriceWnd *TenPriceWnd) getFloat64(ctrlID int32) (float64, error) {
	hwnd := win.GetDlgItem(tenPriceWnd.hwnd, ctrlID)
	if hwnd == 0 {
		return 0, fmt.Errorf("没有找到窗口控件 %d", ctrlID)
	}
	str := winapi.GetWindowText(hwnd)
	value, err := strconv.ParseFloat(str, 64)
	if err != nil {
		return 0, fmt.Errorf("strconv.ParseFloat %s failed, %v", str, err)
	}
	return value, nil
}
func (tenPriceWnd *TenPriceWnd) getUint64(ctrlID int32) (uint64, error) {
	hwnd := win.GetDlgItem(tenPriceWnd.hwnd, ctrlID)
	if hwnd == 0 {
		return 0, fmt.Errorf("没有找到窗口控件 %x", ctrlID)
	}
	str := winapi.GetWindowText(hwnd)
	value, err := strconv.ParseUint(str, 10, 64)
	if err != nil {
		return 0, fmt.Errorf("strconv.ParseFloat %s failed, %v", str, err)
	}
	return value, nil
}
func (tenPriceWnd *TenPriceWnd) getRow(priceCtrlID int32, amountCtrlID int32, name string) (price float64, amount uint64, err error) {
	price, err = tenPriceWnd.getFloat64(priceCtrlID)
	if err != nil {
		return 0, 0, fmt.Errorf("获取 %s 价格错误, %v", name, err)
	}

	amount, err = tenPriceWnd.getUint64(amountCtrlID)
	if err != nil {
		return 0, 0, fmt.Errorf("获取 %s 数量错误, %v", name, err)
	}

	return price, amount, nil
}

// Info 得到十档买卖价格与挂单数量
func (tenPriceWnd *TenPriceWnd) Info() (*TenPriceInfo, error) {
	var info TenPriceInfo
	list := []struct {
		Name         string
		PriceCtrlID  int32
		AmountCtrlID int32
		PriceValue   *float64
		AmountValue  *uint64
	}{
		{
			Name:         "卖五",
			PriceCtrlID:  0x408,
			AmountCtrlID: 0x3fc,
			PriceValue:   &info.Sale5Price,
			AmountValue:  &info.Sale5Amount,
		}, {
			Name:         "卖四",
			PriceCtrlID:  0x409,
			AmountCtrlID: 0x40a,
			PriceValue:   &info.Sale4Price,
			AmountValue:  &info.Sale4Amount,
		}, {
			Name:         "卖三",
			PriceCtrlID:  0x3ff,
			AmountCtrlID: 0x3fb,
			PriceValue:   &info.Sale3Price,
			AmountValue:  &info.Sale3Amount,
		}, {
			Name:         "卖二",
			PriceCtrlID:  0x3fe,
			AmountCtrlID: 0x3f9,
			PriceValue:   &info.Sale2Price,
			AmountValue:  &info.Sale2Amount,
		}, {
			Name:         "卖一",
			PriceCtrlID:  0x3fd,
			AmountCtrlID: 0x3f8,
			PriceValue:   &info.Sale1Price,
			AmountValue:  &info.Sale1Amount,
		}, {
			Name:         "买一",
			PriceCtrlID:  0x3fa,
			AmountCtrlID: 0x3f6,
			PriceValue:   &info.Buy1Price,
			AmountValue:  &info.Buy1Amount,
		}, {
			Name:         "买二",
			PriceCtrlID:  0x401,
			AmountCtrlID: 0x3f5,
			PriceValue:   &info.Buy2Price,
			AmountValue:  &info.Buy2Amount,
		}, {
			Name:         "买三",
			PriceCtrlID:  0x402,
			AmountCtrlID: 0x3f4,
			PriceValue:   &info.Buy3Price,
			AmountValue:  &info.Buy3Amount,
		}, {
			Name:         "买四",
			PriceCtrlID:  0x40b,
			AmountCtrlID: 0x3f7,
			PriceValue:   &info.Buy4Price,
			AmountValue:  &info.Buy4Amount,
		}, {
			Name:         "买五",
			PriceCtrlID:  0x40c,
			AmountCtrlID: 0x40d,
			PriceValue:   &info.Buy5Price,
			AmountValue:  &info.Buy5Amount,
		}, {
			Name:         "涨停",
			PriceCtrlID:  0x404,
			AmountCtrlID: 0x0,
			PriceValue:   &info.UpLimitPrice,
			AmountValue:  nil,
		}, {
			Name:         "跌停",
			PriceCtrlID:  0x405,
			AmountCtrlID: 0x0,
			PriceValue:   &info.DownLimitPrice,
			AmountValue:  nil,
		},
	}
	for _, item := range list {
		hwnd := win.GetDlgItem(tenPriceWnd.hwnd, item.PriceCtrlID)
		if hwnd == 0 {
			return nil, fmt.Errorf("没有找到 %s 价格窗口", item.Name)
		}
		str := winapi.GetWindowText(hwnd)
		value, err := strconv.ParseFloat(str, 64)
		if err != nil {
			return nil, fmt.Errorf("strconv.ParseFloat %s failed, %v", str, err)
		}
		*item.PriceValue = value

		if item.AmountCtrlID > 0 && item.AmountValue != nil {
			hwnd = win.GetDlgItem(tenPriceWnd.hwnd, item.AmountCtrlID)
			if hwnd == 0 {
				return nil, fmt.Errorf("没有找到 %s %x 挂单数量窗口", item.Name, item.AmountCtrlID)
			}
			str = winapi.GetWindowText(hwnd)
			value2, err := strconv.ParseUint(str, 10, 64)
			if err != nil {
				return nil, fmt.Errorf("strconv.ParseFloat %s failed, %v", str, err)
			}
			*item.AmountValue = value2
		}
	}
	return &info, nil
}

// CloseUnimportancePopWindow 关闭不重要的弹出窗口
func CloseUnimportancePopWindow(hwnd win.HWND) {
	winapi.EnumPopupWindow(hwnd, func(popup win.HWND) {
		// fmt.Printf("popup: %x\n", popup)
		title, err := winapi.GetDlgItemText(popup, 0x555)
		if err == nil {
			if title == "安全信息及设置" {
				fmt.Printf("安全信息及设置窗口 关闭\n")
				win.PostMessage(popup, win.WM_CLOSE, 0, 0)
				time.Sleep(time.Second)
			} else if title == "营业部公告" {
				fmt.Printf("营业部公告窗口 关闭\n")
				win.PostMessage(popup, win.WM_CLOSE, 0, 0)
				time.Sleep(time.Second)
			}
		}
	})
}
